//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

/*
 * Copyright (c) 1997, 1998
 *    Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by Bill Paul.
 * 4. Neither the name of the author nor the names of any co-contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

//#pragma warning(disable:4133)  //subtract two pointers of different types
//#pragma warning(disable:4700)

#include <eladef.h>
#include <util/kprint.h>
#include "misc.h"
#include "rtl_net.h"
#include "rtl8139.h"
#include <string.h>
#include "mbuf.h"

//#define _ETHER_DEBUG_

EXTERN_C void * __cdecl Malloc(size_t n);

#define SW_INT(n)               ASM("int %0;": :"i"(n))
#if defined(_mips)
#include <regs.h>
#include <cache.h>
#endif


#define ETHER_NEXT_MULTI(step, enm) \
    /* struct ether_multistep step; */  \
    /* struct ether_multi *enm; */  \
{ \
    if (((enm) = (step).e_enm) != NULL) \
        (step).e_enm = (enm)->enm_next; \
}

#define ETHER_FIRST_MULTI(step, ac, enm) \
    /* struct ether_multistep step; */ \
    /* struct arpcom *ac; */ \
    /* struct ether_multi *enm; */ \
{ \
    (step).e_enm = (ac)->ac_multiaddrs; \
    ETHER_NEXT_MULTI((step), (enm)); \
}

struct ether_multi {
    UInt8 enm_addrlo[6];           /* low  or only address of range */
    UInt8 enm_addrhi[6];           /* high or only address of range */
    struct arpcom *enm_ac;         /* back pointer to arpcom */
    UInt32 enm_refcount;             /* no. claims to this addr/range */
    struct ether_multi *enm_next;  /* ptr to next ether_multi */
};

struct ether_multistep {
    struct ether_multi *e_enm;
};



/*
 * Convert Ethernet address to printable (loggable) representation.
 * This routine is for compatibility; it's better to just use
 *
 *  printf("%6D", <pointer to address>, ":");
 *
 * since there's no static buffer involved.
 */
char *
ether_sprintf(const u_char *ap)
{
    static char etherbuf[18];
//    snprintf(etherbuf, sizeof (etherbuf), "%6D", ap, ":");
    return (etherbuf);
}



/*
 * Default to using PIO access for this driver. On SMP systems,
 * there appear to be problems with memory mapped mode: it looks like
 * doing too many memory mapped access back to back in rapid succession
 * can hang the bus. I'm inclined to blame this on crummy design/construction
 * on the part of RealTek. Memory mapped mode does appear to work on
 * uniprocessor systems though.
 */


#ifdef _MSC_VER
#pragma warning(disable:4028)   //
#pragma warning(disable:4244)   //
#pragma warning(disable:4013)   //
#pragma warning(disable:4047)   //
#pragma warning(disable:4761)   //
#endif




//static pciConfigPtr Rtl8139_Probe(pciConfigPtr *);
static int Rtl8139_Encap(RL_SOFTC *, struct mbuf *);
void __cdecl Rtl8139_Rxeof(RL_SOFTC *);
static void Rtl8139_Txeof(RL_SOFTC *);
static void Rtl8139_Stop(RL_SOFTC *);

static void Rtl8139_Eeprom_Putbyte(RL_SOFTC *, int);
static void Rtl8139_Eeprom_Getword(RL_SOFTC *, int, UInt16 *);
static void Rtl8139_Read_Eeprom(RL_SOFTC *, caddr_t, int, int, int);

static UInt8 Rtl8139_Calchash(caddr_t);
static void Rtl8139_Setmulti(RL_SOFTC *);
static void Rtl8139_Reset(RL_SOFTC *);
static int Rtl8139_Var_Init(RL_SOFTC *);

int    RTL8139Initalize(RL_SOFTC *  pThis);
int    RTL8139Xmit(RL_SOFTC*  pThis);
ECode  RTL8139Ioctl(RL_SOFTC* pThis, UInt32 command);
static void CDECL RTL8139Isr(irq_t , void *, InterruptContext *);
Boolean   RTL8139Interrupt(void*  pThis);

void   RTL8139Watchdog(RL_SOFTC* pThis);


#define EE_SET(x)                           \
    CSR_WRITE_1(pThis, RL_EECMD,            \
        CSR_READ_1(pThis, RL_EECMD) | x)

#define EE_CLR(x)                           \
    CSR_WRITE_1(pThis, RL_EECMD,            \
        CSR_READ_1(pThis, RL_EECMD) & ~x)

void DELAY(int n) {
    n = n*0x03f;
    while(n > 0) {
        n--;
    }
}

/*
 * Send a read command and address to the EEPROM, check for ACK.
 */
static void
Rtl8139_Eeprom_Putbyte(RL_SOFTC *pThis, int addr)
{
    register int d, i;

    d = addr | RL_EECMD_READ;

    /*
     * Feed in each bit and strobe the clock.
     */
    for (i = 0x400; i; i >>= 1) {
        if (d & i) {
            EE_SET(RL_EE_DATAIN);
        } else {
            EE_CLR(RL_EE_DATAIN);
        }
        DELAY(100);
        EE_SET(RL_EE_CLK);
        DELAY(150);
        EE_CLR(RL_EE_CLK);
        DELAY(100);
    }

    return;
}

/*
 * Read a word of data stored in the EEPROM at address 'addr.'
 */
static void
Rtl8139_Eeprom_Getword(RL_SOFTC *pThis, int addr, UInt16 *dest)
{
    register int  i;
    UInt16        word = 0;

    /*
     * Enter EEPROM access mode.
     */
    CSR_WRITE_1(pThis, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL);

    /*
     * Send address of word we want to read.
     */
    Rtl8139_Eeprom_Putbyte(pThis, addr);

    CSR_WRITE_1(pThis, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL);

    /*
     * Start reading bits from EEPROM.
     */
    for (i = 0x8000; i; i >>= 1) {
        EE_SET(RL_EE_CLK);
        DELAY(50);
        if (CSR_READ_1(pThis, RL_EECMD) & RL_EE_DATAOUT)
            word |= i;
        EE_CLR(RL_EE_CLK);
        DELAY(50);
    }

    /* Turn off EEPROM access mode. */
    CSR_WRITE_1(pThis, RL_EECMD, RL_EEMODE_OFF);

    *dest = word;

    return;
}

/*
 * Read a sequence of words from the EEPROM.
 */
static void
Rtl8139_Read_Eeprom(RL_SOFTC *pThis, caddr_t dest, int off, int cnt, int swap)
{
    int      i;
    UInt16   word = 0, *ptr;

    for (i = 0; i < cnt; i++) {
        Rtl8139_Eeprom_Getword(pThis, off + i, &word);
        ptr = (UInt16 *)(dest + (i * 2));
        if (swap)
            *ptr = ntohs(word);
        else
            *ptr = word;
    }

    return;
}


/*
 * Calculate CRC of a multicast group address, return the upper 6 bits.
 */
static UInt8
Rtl8139_Calchash(caddr_t addr)
{
    UInt32    crc, carry;
    int       i, j;
    UInt8     c;

    /* Compute CRC for the address value. */
    crc = 0xFFFFFFFF; /* initial value */

    for (i = 0; i < 6; i++) {
        c = *(addr + i);
        for (j = 0; j < 8; j++) {
            carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
            crc <<= 1;
            c >>= 1;
            if (carry)
                crc = (crc ^ 0x04c11db6) | carry;
        }
    }

    /* return the filter bit position */
    return(crc >> 26);
}

/*
 * Program the 64-bit multicast hash filter.
 */
static void
Rtl8139_Setmulti(RL_SOFTC *pThis)
{
    struct ifnet_             *ifp = &pThis->if_handle->arpcom.ac_if;
    struct arpcom_            *ac = &pThis->if_handle->arpcom;
    struct ether_multi       *enm;
    struct ether_multistep   step;
    int            h = 0;
    UInt32         hashes[2] = { 0, 0 };
    UInt32         rxfilt;
    int            mcnt = 0;

    rxfilt = CSR_READ_4(pThis, RL_RXCFG);

    if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
        rxfilt |= RL_RXCFG_RX_MULTI;
        CSR_WRITE_4(pThis, RL_RXCFG, rxfilt);
        CSR_WRITE_4(pThis, RL_MAR0, 0xFFFFFFFF);
        CSR_WRITE_4(pThis, RL_MAR4, 0xFFFFFFFF);
        return;
    }

    /* first, zot all the existing hash bits */
    CSR_WRITE_4(pThis, RL_MAR0, 0);
    CSR_WRITE_4(pThis, RL_MAR4, 0);

    /* now program new ones */
    ETHER_FIRST_MULTI(step, ac, enm);
    while (enm != NULL) {
        mcnt++;
        h = Rtl8139_Calchash(enm->enm_addrlo);
        if (h < 32)
            hashes[0] |= (1 << h);
        else
            hashes[1] |= (1 << (h - 32));
        mcnt++;
        ETHER_NEXT_MULTI(step, enm);
     }

    if (mcnt)
        rxfilt |= RL_RXCFG_RX_MULTI;
    else
        rxfilt &= ~RL_RXCFG_RX_MULTI;

    CSR_WRITE_4(pThis, RL_RXCFG, rxfilt);
    CSR_WRITE_4(pThis, RL_MAR0, hashes[0]);
    CSR_WRITE_4(pThis, RL_MAR4, hashes[1]);

    return;
}

static void
Rtl8139_Reset(RL_SOFTC *pThis)
{
    register int        i;

    CSR_WRITE_1(pThis, RL_COMMAND, RL_CMD_RESET);

    for (i = 0; i < RL_TIMEOUT; i++) {
        DELAY(10);
        if (!(CSR_READ_1(pThis, RL_COMMAND) & RL_CMD_RESET))
            break;
    }
    if (i == RL_TIMEOUT)
        kprintf("Error:rl%d: reset never completed!\n", pThis->rl_unit);

    return;
}



u_char    eaddr[ETHER_ADDR_LEN+1];
static int
rl_init(RL_SOFTC *pThis, int unit)
{

    int       rl_did = 0;
    int i = 0;
    /* Reset the adapter. */
    Rtl8139_Reset(pThis);

    /*
     * Get station address from the EEPROM.
     */
    Rtl8139_Read_Eeprom(pThis, (caddr_t)&eaddr[0], RL_EE_EADDR, 3, 0);

    /*
     * A RealTek chip was detected. Inform the world.
     */
    eaddr[6] = '\0';
    kprintf("rl%d: Ethernet address: ", unit);
    for(i = 0; i <= ETHER_ADDR_LEN-1; i++) {
        kprintf("%d %02x ", i, eaddr[i]);
    }
    kprintf("\n");

    pThis->rl_unit = unit;

    /*
     * Now read the exact device type from the EEPROM to find
     * out if it's an 8129 or 8139.
     */
    Rtl8139_Read_Eeprom(pThis, (caddr_t)&rl_did, RL_EE_PCI_DID, 1, 0);

    if (rl_did == RT_DEVICEID_8139 || rl_did == ACCTON_DEVICEID_5030 ||
        rl_did == DELTA_DEVICEID_8139 || rl_did == ADDTRON_DEVICEID_8139 ||
        rl_did == DLINK_DEVICEID_530TXPLUS)
        pThis->rl_type = RL_8139;
    else if (rl_did == RT_DEVICEID_8129)
        pThis->rl_type = RL_8129;
    else {
        kprintf("Error:rl%d: unknown device ID: %x\n", unit, rl_did);
        return -1;
    }
    kprintf("rl%d: Device ID: %x\n", unit, rl_did);

    {
//        PIADDRESSSPACE pIAddr;
//        ECode   Rc;
//        Address Addr = 0;
        char * pAddr;

#ifdef _ETHER_DEBUG_
    kprintf("%d %d\n", RL_RXBUFLEN + 1518, mRoundUp2Order((RL_RXBUFLEN
        + 1518)/(4*1024)));
#endif

        pAddr = (char*)KernelAlloc(
            mRoundUp2Order((RL_RXBUFLEN + 1518 + 4*1024 - 1)/(4*1024)));
        if (pAddr == NULL) {
            kprintf("Error: Could not malloc.\n");
        }

//        pThis->readBuf = (char*)KernelAlloc(mRoundUp2Order(
//            (RL_RXBUFLEN + 1518 + 4)/(4*1024)));

//        pIAddr = CurrentAddressSpace();

//        Rc = pIAddr->v->Allocate(pIAddr, &Addr, RL_RXBUFLEN + 1518);
//        if (FAILED(Rc)) {
//            kprintf("Could not allocate (%x)\n", Rc);
//            return -1;
//        }
//
//        Rc = pIAddr->v->Commit(pIAddr, Addr, RL_RXBUFLEN + 1518,
//                ADDR_COMMIT_CONTIGUOUS | ADDR_COMMIT_LOCK);
//        if (FAILED(Rc)) {
//            kprintf("Could not commit (%x)\n", Rc);
//            return -1;
//        }

//        pThis->rl_cdata.rl_rx_buf = (char *)Addr;
        pThis->rl_cdata.rl_rx_buf = (char *)pAddr;

        /*
         * Get phys address for it
         */
//        Rc = GetPhysicalAddress(Addr, (void *)pThis->rl_cdata.rl_rx_buf);
//        if (FAILED(Rc)) {
//            kprintf("GetPhys failed on %x (%x)\n", Addr, Rc);
//            return -1;
//        }

//        pThis->pmtx = (void*)Malloc(sizeof(struct mtx));
//        Mtx_init(pThis->pmtx); //for read buf

#if 0
        pThis->rl_cdata.rl_rx_buf = (char *)PhysAddr(pAddr);

        kprintf("\n AAA addr = %08x p = %08x\n", pAddr, pThis->rl_cdata.rl_rx_buf);

        if (pThis->rl_cdata.rl_rx_buf == NULL) {
            kprintf("Error:rl%d: no memory for list buffers!\n", unit);
            return -1;
        }
#endif

        /* Leave a few bytes before the start of the RX ring buffer. */
        pThis->rl_cdata.rl_rx_buf_ptr = pThis->rl_cdata.rl_rx_buf;
        pThis->rl_cdata.rl_rx_buf += sizeof(UInt64);
    }
    return 0;
}


static RL_SOFTC * rtl_sc;

RL_SOFTC *
RTL8139New(int * pPortBase, int * pIrq, int* pMedia)
{
    RL_SOFTC     *pThis;
//    UInt32       command;
//    int          error = 0;
    static int   unit = 0;
//    pciConfigPtr *pcrpp, pcrp;
//    pciTagRec    tag;
//    UInt32       iobase = 0, membase = 0, irq = 0;

#if defined(_mips)
    *pPortBase = *pPortBase + K1BASE;
#endif

//    pcrpp = scanpci(0);
//    pcrp = Rtl8139_Probe(pcrpp);
//    if (pcrp == NULL) {
//        kprintf("not found rtl8139 card\n");
//        return 0;
//    }

    pThis = (RL_SOFTC *)Malloc(sizeof(RL_SOFTC));
    if (pThis == NULL) {
        kprintf("Error:Could not allocate %d bytes\n", sizeof *pThis);
        return NULL;
    }
    bzero(pThis, sizeof(RL_SOFTC));

    /*
     * Handle power management nonsense.
     */
//    tag = pcibusTag(pcrp->_bus, pcrp->_cardnum, pcrp->_func);
//    command = pciReadLong(tag, RL_PCI_CAPID) & 0xFF;
//
//    if (command == 0x01) {
//         command = pciReadLong(tag, RL_PCI_PWRMGMTCTRL) & 0x0000FFFF;
//        if (command & RL_PSTATE_MASK) {
//
//            /* Save important PCI config data. */
//             iobase = pciReadLong(tag, RL_PCI_LOIO) & 0xFF00;
//             membase = pciReadLong(tag, RL_PCI_LOMEM) & 0xFFFF0000;
//             irq = pciReadLong(tag, RL_PCI_INTLINE) & 0xFF;
//
//            /* Reset the power state. */
//            kprintf("rl%d: chip is is in D%d power mode "
//                   L"-- setting to D0\n", unit, command & RL_PSTATE_MASK);
//
//            command &= 0xFFFFFFFC;
//            writepci(0, pcrp->_bus,pcrp->_cardnum,
//                     pcrp->_func, RL_PCI_PWRMGMTCTRL, ~0, command);
//
//            /* Restore PCI config data. */
//             writepci(0, pcrp->_bus,pcrp->_cardnum,
//                         pcrp->_func, RL_PCI_LOIO, ~0, iobase);
//             writepci(0, pcrp->_bus,pcrp->_cardnum,
//                         pcrp->_func, RL_PCI_LOMEM, ~0, membase);
//             writepci(0, pcrp->_bus,pcrp->_cardnum,
//                         pcrp->_func, RL_PCI_INTLINE, ~0, irq);
//        }
//    }

//    pThis->iotag = 0;
//    if (iobase == 0)
//        pThis->iobase = *pPortBase;
//    else
//        pThis->iobase = iobase;
//
//    if (irq == 0)
//        pThis->irq = *pIrq;
//    else
//        pThis->irq = irq;

//config iobase and irq
    pThis->pIntrPoint = (struct Signal *)Malloc(sizeof(struct Signal));
    pThis->pReadSignal = (struct Signal *)Malloc(sizeof(struct Signal));
    pThis->iobase = *pPortBase;
    pThis->irq = *pIrq;

//registry irq;
    AddDevice(pThis->irq, IPL10, RTL8139Isr, pThis);

#if defined(_mips)
    pThis->irq = 41;
    *pIrq = 41;
#endif

#ifdef _ETHER_DEBUG_
kprintf("before Rtl8139 new\n");
#endif

    if (rl_init(pThis, unit)) {
        kprintf("Init Card Error\n");
        return NULL;
    }
//__asm__("int $3");
//kprintf("In Rtl8139 initialization\n");

    pThis->if_handle = NULL;
    rtl_sc = pThis;

#ifdef _ETHER_DEBUG_
kprintf("after Rtl8139 new\n");
#endif

    return (void *)pThis;
}


int
Rtl8139_Connect(RL_SOFTC ** rl_sc, Rtl8139 * if_sc)
{
    //Create irq thread call RTL8139Interrupt with rtl_sc
    Signal_init(rtl_sc->pIntrPoint);
    Signal_init(rtl_sc->pReadSignal);

#ifdef _ETHER_DEBUG_
    kprintf("\nRtl8139_Connect kernel R R %08x %08x\n", rtl_sc, rtl_sc->pReadSignal);
#endif

    rtl_sc->if_handle = (void *)if_sc;

    *rl_sc = rtl_sc;

    CreateThread(rtl_sc);

#ifdef _ETHER_DEBUG_
    //copy mac address
    kprintf("\n sizeof net %d \n", sizeof(struct ifnet_));
    kprintf("\n sizeof data %d \n", sizeof(struct if_data_));
    kprintf("\n sizeof queue %d \n", sizeof(struct ifqueue_));
    kprintf("\n sizeof sizeifnet %d \n", if_sc->arpcom.ac_if.sizeifnet);
    kprintf("\n kernel data addr %08x \n", rtl_sc);
#endif

    if (if_sc->arpcom.ac_if.sizeifnet == sizeof(struct ifnet_)) {
        memcpy(&(if_sc->arpcom.ac_enaddr[0]), &eaddr[0], 6);
    }else {
        kprintf("\nerror ? (-) Connect\n");
    }
    return 0;
}


struct timeval tv1,tv2,tv3,tv4,tv5,tv;

void __cdecl InterruptThread(void* pArg)
{

#ifdef _ETHER_DEBUG_
    kprintf("\n(-) InterruptThread\n");
#endif
    int ret = 0;
    RL_SOFTC *pThis = pArg;
    RTL8139Initalize(pThis);
    while (1) {
        getmicrotime(&tv);
        Wait(pThis->pIntrPoint, &ret);
//        kprintf(" AW_%d ", ret);
        getmicrotime(&tv2);
//        if (tv2.tv_sec - tv1.tv_sec > 1){
//            kprintf("tv0=%d\n",tv2.tv_sec - tv1.tv_sec);
//            kprintf("BNtv1=%d %d\n", tv1.tv_sec, tv1.tv_usec);
//            kprintf("ANtv5=%d %d\n",tv5.tv_sec, tv5.tv_usec);
//            kprintf("BWtv=%d %d\n",tv.tv_sec, tv.tv_usec);
//            kprintf("AWtv2=%d %d\n",tv2.tv_sec, tv2.tv_usec);
//            kprintf("Wtv4=%d\n",tv2.tv_sec - tv.tv_sec);
//            __asm__("int $3");
//        }
        RTL8139Interrupt(pArg);
    }
    return;
}


/*
 * Initialize the transmit descriptors.
 */
static int
Rtl8139_Var_Init(RL_SOFTC *pThis)
{
    int            i;
    struct rl_chain_data    *cd;

    {
        cd = &pThis->rl_cdata;
        for (i = 0; i < RL_TX_LIST_CNT; i++) {
            cd->rl_tx_chain[i] = NULL;
            CSR_WRITE_4(pThis, RL_TXADDR0 + (i * sizeof(UInt32)), 0x0);
        }
        pThis->rl_cdata.cur_tx = 0;
        pThis->rl_cdata.last_tx = 0;
    }

    return(0);
}


/*
 * A frame has been uploaded: pass the resulting mbuf chain up to
 * the higher level protocols.
 *
 * You know there's something wrong with a PCI bus-master chip design
 * when you have to use m_devget().
 *
 * The receive operation is badly documented in the datasheet, so I'll
 * attempt to document it here. The driver provides a buffer area and
 * places its base address in the RX buffer start address register.
 * The chip then begins copying frames into the RX buffer. Each frame
 * is preceeded by a 32-bit RX status word which specifies the length
 * of the frame and certain other status bits. Each frame (starting with
 * the status word) is also 32-bit aligned. The frame length is in the
 * first 16 bits of the status word; the lower 15 bits correspond with
 * the 'rx status register' mentioned in the datasheet.
 *
 * Note: to make the Alpha happy, the frame payload needs to be aligned
 * on a 32-bit boundary. To achieve this, we cheat a bit by copying from
 * the ring buffer starting at an address two bytes before the actual
 * data location. We can then shave off the first two bytes using m_adj().
 * The reason we do this is because m_devget() doesn't let us specify an
 * offset into the mbuf storage space, so we have to artificially create
 * one. The ring is allocated in such a way that there are a few unused
 * bytes of space preceecing it so that it will be safe for us to do the
 * 2-byte backstep even if reading from the ring at offset 0.
 */


void __cdecl
Rtl8139_Rxeof(RL_SOFTC *pThis)
{
        struct ifnet_        *ifp;
        int           total_len = 0;
        UInt32        rxstat;
        caddr_t       rxbufpos;
        int           wrap = 0;
        UInt16        cur_rx;
        UInt16        limit;
        UInt16        rx_bytes = 0, max_bytes;
        int           isreverse = 0;
        int           isempty = 0;
        int           head = 0;
        int           tail = 0;
        int           BUFFLEN = 0;
        struct queue * pBuf;
        int           num = 0;
//        unsigned char * data;

        BUFFLEN = pThis->size;

        ifp = &pThis->if_handle->arpcom.ac_if;
        /* 16 means 64bit sychronous singnal and 64bit buf ring*/
        cur_rx = (CSR_READ_2(pThis, RL_CURRXADDR) + 16) % RL_RXBUFLEN;

        /* Do not try to read past this point. */
        limit = CSR_READ_2(pThis, RL_CURRXBUF) % RL_RXBUFLEN;

        if (limit < cur_rx)
            max_bytes = RL_RXBUFLEN - (cur_rx - limit);
        else
            max_bytes = limit - cur_rx;

//        pThis->size = sizeof(int);
//        pointer = pThis->readBuf + sizeof(int);

        while((CSR_READ_1(pThis, RL_COMMAND) & RL_CMD_EMPTY_RXBUF) == 0) {
            rxbufpos = pThis->rl_cdata.rl_rx_buf + cur_rx;

#if (MIPS_ENABLE_CACHE == 1)
            dma_cache_inv((Address)rxbufpos, 4);
#endif

            rxstat = *(UInt32 *)rxbufpos;

            /*
             * Here's a totally undocumented fact for you. When the
             * RealTek chip is in the process of copying a packet into
             * RAM for you, the length will be 0xfff0. If you spot a
             * packet header with this value, you need to stop. The
             * datasheet makes absolutely no mention of this and
             * RealTek should be shot for this.
             */
            if ((UInt16)(rxstat >> 16) == RL_RXSTAT_UNFINISHED)
                break;

            if (!(rxstat & RL_RXSTAT_RXOK)) {
                ifp->if_ierrors++;
                RTL8139Initalize(pThis);
                return;
            }

            /* No errors; receive the packet. */
            total_len = rxstat >> 16;
            /* 4  means the spzce of  total_len in rx*/
            rx_bytes += total_len + 4;

            /*
             * XXX The RealTek chip includes the CRC with every
             * received frame, and there's no way to turn this
             * behavior off (at least, I can't find anything in
             * the manual that explains how to do it) so we have
             * to trim off the CRC manually.
             */
            total_len -= ETHER_CRC_LEN;

            /*
             * Avoid trying to read more bytes than we know
             * the chip has prepared for us.
             */
            if (rx_bytes > max_bytes)
                break;

            rxbufpos = pThis->rl_cdata.rl_rx_buf +
                ((cur_rx + sizeof(UInt32)) % RL_RXBUFLEN);

            if (rxbufpos == (pThis->rl_cdata.rl_rx_buf + RL_RXBUFLEN))
                rxbufpos = pThis->rl_cdata.rl_rx_buf;

            wrap = (pThis->rl_cdata.rl_rx_buf + RL_RXBUFLEN) - rxbufpos;

#if (MIPS_ENABLE_CACHE == 1)
			dma_cache_inv((Address)((Address)(rxbufpos - RL_ETHER_ALIGN) & ~3),	// round down
						  ((total_len + RL_ETHER_ALIGN + 3) & ~3));
#endif

//			m = m_devget(rxbufpos - RL_ETHER_ALIGN,
//                    total_len + RL_ETHER_ALIGN, 0, ifp, NULL);

            pBuf = (struct queue *)pThis->readBuf;
            //avoid conflict, so duplicate the head value.
            head = pBuf->head;
            tail = pBuf->tail;
            //the tail has went over the boundary of buffer;
            if ((tail + total_len + sizeof(int)) > BUFFLEN) {
                isreverse = 1;
            }
            else{
                isreverse = 0;
            }
            //if the queue is waiting for data
            if (tail == head) {
                isempty = 1;
            }
            else {
                isempty = 0;
            }
            //if the ring-queue is full, drop this frame;
            if (tail < head && (tail + total_len + sizeof(int))%BUFFLEN >= head
                    && !isreverse) {
//                kprintf("the queue is full! this frame will be droped.");

                if (total_len > wrap) {
                    cur_rx = (total_len - wrap + ETHER_CRC_LEN);
                }
                else {
                    cur_rx += total_len + 4 + ETHER_CRC_LEN;
                }
                cur_rx = (cur_rx + 3) & ~3;
                CSR_WRITE_2(pThis, RL_CURRXADDR, cur_rx - 16);

                return;
            }
            if (tail < head && (tail + total_len + sizeof(int))%BUFFLEN <= head
                    && isreverse) {
//                kprintf("the queue is full! this frame will be droped.");

                if (total_len > wrap) {
                    cur_rx = (total_len - wrap + ETHER_CRC_LEN);
                }
                else {
                    cur_rx += total_len + 4 + ETHER_CRC_LEN;
                }
                cur_rx = (cur_rx + 3) & ~3;
                CSR_WRITE_2(pThis, RL_CURRXADDR, cur_rx - 16);

                return;
            }
            if (tail > head && (tail + total_len + sizeof(int))%BUFFLEN >= head
                    && isreverse) {
//                kprintf("the queue is full! this frame will be droped.");

                if (total_len > wrap) {
                    cur_rx = (total_len - wrap + ETHER_CRC_LEN);
                }
                else {
                    cur_rx += total_len + 4 + ETHER_CRC_LEN;
                }
                cur_rx = (cur_rx + 3) & ~3;
                CSR_WRITE_2(pThis, RL_CURRXADDR, cur_rx - 16);

                return;
            }

            (*(int *)(pBuf->g_buf + tail)) = total_len;

//kprintf(" Rxeof ");

//     data = pBuf->g_buf + tail + sizeof(int);
//     if (*(unsigned int*)(data+14+12) == 0x1e01a8c0) {
//        //kprintf("len = %d off = 0x%x\n", total_len,  *(unsigned char*)(data+14+6));
//        if (total_len >= 1000) {
//            //kprintf("24 firstchar %c lastchar %c\n", *(data+14+28), *(data+14+28+1471));
//            kprintf("packet_%d ", total_len);
//        }
//     }

            //now, we got enough space to fill in
            memcpy(pBuf->g_buf + tail + sizeof(int), rxbufpos, total_len);
            if (total_len > wrap) {
                memcpy(pBuf->g_buf + tail + sizeof(int) + wrap,
                        pThis->rl_cdata.rl_rx_buf, total_len - wrap);
                cur_rx = (total_len - wrap + ETHER_CRC_LEN);

            }
            else {
                cur_rx += total_len + 4 + ETHER_CRC_LEN;
            }
            //if the data need to be reversed
            if (isreverse) {
                memcpy(pBuf->g_buf, pBuf->g_buf + BUFFLEN,
                    (tail + total_len + sizeof(int)) - BUFFLEN);
            }

//            if (rxbufpos + total_len < pThis->rl_cdata.rl_rx_buf +
//                    RL_RXBUFLEN + 1518 && total_len < 1518) {
//                //kprintf("fr:%08x la:%08x\n", rxbufpos, rxbufpos + total_len);
//                memcpy(pointer + sizeof(int), rxbufpos, total_len);
//            }
//            else {
//                kprintf("outof special memory field.\n");
//                RTL8139Initalize(pThis);
//                return;
//            }

//            if (total_len > wrap) {

                /*
                 * Fool m_devget() into thinking we want to copy
                 * the whole buffer so we don't end up fragmenting
                 * the data.
                 */
//                if (m == NULL) {
//                    ifp->if_ierrors++;
//                    kprintf("rl%d: out of mbufs, tried to "
//                        L"copy %d bytes\n", pThis->rl_unit, wrap);
//                } else {
//                    m_adj(m, RL_ETHER_ALIGN);
//                    m_copyback(m, wrap, total_len - wrap,
//                        pThis->rl_cdata.rl_rx_buf);

//                      memcpy(pointer + sizeof(int) + wrap,
//                        pThis->rl_cdata.rl_rx_buf, total_len - wrap);
//                }

//                cur_rx = (total_len - wrap + ETHER_CRC_LEN);
//            } else {
//                if (m == NULL) {
//                    ifp->if_ierrors++;
//                    kprintf("rl%d: out of mbufs, tried to "
//                        L"copy %d bytes\n", pThis->rl_unit, total_len);
//                } else {
//                    m_adj(m, RL_ETHER_ALIGN);
//                }
//                cur_rx += total_len + 4 + ETHER_CRC_LEN;
//            }


            /*
             * Round up to 32-bit boundary.
             */
            cur_rx = (cur_rx + 3) & ~3;
            CSR_WRITE_2(pThis, RL_CURRXADDR, cur_rx - 16);

            //move the tail point
            pBuf->tail = (tail + total_len + sizeof(int))%BUFFLEN;

//            if (m == NULL)
//                continue;
//
//            eh = mtod(m, struct ether_header *);
//            ifp->if_ipackets++;

            /* Remove header from mbuf and pass it on. */
//#ifdef __NETNEW
//            ether_input(ifp,/* eh, */m);
//#else
//            m_adj(m, sizeof(struct ether_header));
//            ether_input(ifp, eh, m);
//#endif
            //if the queue is waiting for data, now wake it up.
            if (isempty) {
                getmicrotime(&tv3);
                Pulse(pThis->pReadSignal, num);
            }
        }
    return;
}

/*
 * A frame was downloaded to the chip. It's safe for us to clean up
 * the list buffers.
 */
static void
Rtl8139_Txeof(RL_SOFTC *pThis)
{

        struct ifnet_  *ifp;
        UInt32        txstat;

        ifp = &pThis->if_handle->arpcom.ac_if;

        /* Clear the timeout timer. */
        ifp->if_timer = 0;

        /*
         * Go through our tx list and free mbufs for those
         * frames that have been uploaded.
         */
        do {
            txstat = CSR_READ_4(pThis, RL_LAST_TXSTAT(pThis));
            if (!(txstat & (RL_TXSTAT_TX_OK|
                RL_TXSTAT_TX_UNDERRUN|RL_TXSTAT_TXABRT)))
                break;

            /*  Add collision counter */
            ifp->if_collisions += (txstat & RL_TXSTAT_COLLCNT) >> 24;

            if (RL_LAST_TXMBUF(pThis) != NULL) {
                /*  Free Buffer */

                /*
                 * RL_LAST_TXMBUF(x)==>
                 *         (x->rl_cdata.rl_tx_chain[x->rl_cdata.last_tx])
                 */
                m_freem(RL_LAST_TXMBUF(pThis));
                RL_LAST_TXMBUF(pThis) = NULL;
            }

            if (txstat & RL_TXSTAT_TX_OK) {
                 /*  Case Tx OK */
                ifp->if_opackets++;
            }
            else {                    /*  Case Tx ERR */
                int   oldthresh;

                ifp->if_oerrors++;
                if ((txstat & RL_TXSTAT_TXABRT) ||
                    (txstat & RL_TXSTAT_OUTOFWIN))
                    CSR_WRITE_4(pThis, RL_TXCFG, RL_TXCFG_CONFIG);
                oldthresh = pThis->rl_txthresh;
                /* error recovery */
                Rtl8139_Reset(pThis);
                RTL8139Initalize(pThis);
                /*
                 * If there was a transmit underrun,
                 * bump the TX threshold.
                 */
                if (txstat & RL_TXSTAT_TX_UNDERRUN)
                    pThis->rl_txthresh = oldthresh + 32;
                return;
            }

            RL_INC(pThis->rl_cdata.last_tx);
            ifp->if_flags &= ~IFF_OACTIVE;
        } while (pThis->rl_cdata.last_tx != pThis->rl_cdata.cur_tx);

    return;
}

//struct timeval time;
//void CDECL RTL8139Isr(irq_t irq, void *pvDevice, InterruptContext *pContext)
//{
//    UInt16        status;
//    RL_SOFTC * pThis = pvDevice;
//    UInt16      isrmask = CSR_READ_2(pThis, RL_IMR);
//    /* Disable interrupts. */
//    CSR_WRITE_2(pThis, RL_IMR, 0x0000);
//	//for(;;){
//	getmicrotime(&time);
//        	status = CSR_READ_2(pThis, RL_ISR);
//        	pThis->status = status;
//        	if (status)
//                	CSR_WRITE_2(pThis, RL_ISR, status);
//
//        	if ((status & RL_INTRS) == 0) {
//            		return;
//        	}
//
//        	if (status & RL_RX_INTRS) {
//            		CSR_WRITE_2(pThis, RL_IMR, 0xfffc&isrmask);
//            		PulseByISR(pThis->pReadSignal);
//        	}
//        	/* Wakeup handler thread and we are done. */
//        	if (status & RL_NORMAL_INTRS) {
//            		CSR_WRITE_2(pThis, RL_IMR, 0x3&isrmask);
//            		PulseByISR(pThis->pIntrPoint);
//        	}
//	//}
//    return ;
//}
//
//
//EXTERN_C Boolean  RTL8139Interrupt(void*  pArg)
//{
//    RL_SOFTC*  pThis = (RL_SOFTC* )pArg;
//    struct ifnet_  *ifp = &pThis->if_handle->arpcom.ac_if;
//    UInt16        status;
//    UInt16        isrmask;
//
//   //for (;;) {
//   //     status = CSR_READ_2(pThis, RL_ISR);
//     //   if (status)
//     //      CSR_WRITE_2(pThis, RL_ISR, status);
//        status = pThis->status;
////kprintf("Interrupt %08x %d\n", status, __LINE__);
//        //if ((status & RL_NORMAL_INTRS) == 0)
//        //   break;
//
//        if ((status & RL_ISR_TX_OK) || (status & RL_ISR_TX_ERR)) {
//            Rtl8139_Txeof(pThis);
//        }
//
//        if (status & RL_ISR_SYSTEM_ERR) {
//            Rtl8139_Reset(pThis);
//            RTL8139Initalize(pThis);
//        }
//   // }
//
//
//    /* Re-enable interrupts. */
//    isrmask = CSR_READ_2(pThis, RL_IMR);
//    CSR_WRITE_2(pThis, RL_IMR, RL_NORMAL_INTRS|isrmask);
//    if (ifp->if_snd.ifq_head != NULL)  {
//        /* Data in Tx buffer waiting for transimission */
//        kprintf("\nxmitttttt\n");
//        RTL8139Xmit((void *)ifp);
//    }
//
//    return 0;
//}
static int uu = 0;
void CDECL BspWriteConsole(const char *szMessage);
void CDECL RTL8139Isr(irq_t irq, void *pvDevice, InterruptContext *pContext)
{
    /* Disable interrupts. */
    RL_SOFTC * pThis = pvDevice;
    CSR_WRITE_2(pThis, RL_IMR, 0x0000);
    getmicrotime(&tv1);
    uu++;
//kprintf(" I_%d ", uu);
  	PulseByISR(pThis->pIntrPoint, uu);
    getmicrotime(&tv5);
    return ;
}

EXTERN_C Boolean  RTL8139Interrupt(void*  pArg)
{
    RL_SOFTC*  pThis = (RL_SOFTC* )pArg;
    struct ifnet_  *ifp = &pThis->if_handle->arpcom.ac_if;
    UInt16        status;

    for (;;) {
        status = CSR_READ_2(pThis, RL_ISR);

        if (status)
            CSR_WRITE_2(pThis, RL_ISR, status);

        if ((status & RL_INTRS) == 0)
            break;

        if ((status & RL_ISR_RX_OK) || (status & RL_ISR_RX_ERR)) {
//kprintf("\n+ + + +%08x %d \n", status, __LINE__);
//kprintf(" I-R ");
            Rtl8139_Rxeof(pThis);
        }

        if ((status & RL_ISR_TX_OK) || (status & RL_ISR_TX_ERR)) {
            Rtl8139_Txeof(pThis);
        }

        if (status & RL_ISR_SYSTEM_ERR) {
            Rtl8139_Reset(pThis);
            RTL8139Initalize(pThis);
        }
    }

    /* Re-enable interrupts. */
    CSR_WRITE_2(pThis, RL_IMR, RL_INTRS);

    if (ifp->if_snd.ifq_head != NULL)  {
        //kprintf("\nxmittttttttttttttttttttttttttttttttttttttt\n");
		;
        /* Data in Tx buffer waiting for transimission */
        //RTL8139Xmit((void *)ifp);
    }

    return 0;
}

/*
 * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
 * pointers to the fragment pointers.
 */
static int
Rtl8139_Encap(RL_SOFTC *pThis, struct mbuf *m_head)
{
    struct mbuf        *m_new = NULL;


    m_new = m_gethdr(M_DONTWAIT, MT_DATA);

    if (m_new == NULL) {
        kprintf("Error:rl%d: no memory for tx list", pThis->rl_unit);
        return(1);
    }

    if (m_head->m_pkthdr.len > MHLEN) {
        m_clget(m_new, M_DONTWAIT);
        if (!(m_new->m_flags & M_EXT)) {
            m_freem(m_new);
            kprintf("Error:rl%d: no memory for tx list",
                    pThis->rl_unit);
            return(1);
        }
    }
    m_copydata(m_head, 0, m_head->m_pkthdr.len, mtod(m_new, caddr_t));
//    SW_INT(3);
#if 0//debug
    memset(mtod(m_new, caddr_t), 1, m_head->m_pkthdr.len);
#endif//if 0
    m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
//    m_freem(m_head);

    m_head = m_new;

    /* Pad frames to at least 60 bytes. */
    if (m_head->m_pkthdr.len < RL_MIN_FRAMELEN) {
        /*  Case length < 60 bytes */
        /*
         * Make security concious people happy: zero out the
         * bytes in the pad area, since we don't know what
         * this mbuf cluster buffer's previous user might
         * have left in it.
          */
        bzero(mtod(m_head, char *) + m_head->m_pkthdr.len,
             RL_MIN_FRAMELEN - m_head->m_pkthdr.len);
        m_head->m_pkthdr.len +=
            (RL_MIN_FRAMELEN - m_head->m_pkthdr.len);
        m_head->m_len = m_head->m_pkthdr.len;
    }


    RL_CUR_TXMBUF(pThis) = m_head;        /*  Save pointer of buffer to pThis */

    return(0);
}


int RTL8139Xmit(RL_SOFTC* pThis)
{
    struct ifnet_        *ifp = &pThis->if_handle->arpcom.ac_if;
    struct mbuf          *m_head = NULL;
	Address addr;

        while(RL_CUR_TXMBUF(pThis) == NULL) {
            /*
             * RL_CUR_TXMBUF(x)==>
             *  (x->rl_cdata.rl_tx_chain[x->rl_cdata.cur_tx])
             */

            /*  Remove(get) data from system transmit queue */
            IF_DEQUEUE(&ifp->if_snd, m_head);

//            if (m_head) {
//	char * data = NULL;
//                data = (char*)mtod(m_head, char*);
//                kprintf("RTL8139Xmit m_head %08x %08x %08x\n", *data,*(data+1),*(data+2));
//                kprintf("mbuf len is: %d\n", m_head->m_len);
//                if(m_head->m_len>42)
//                __asm__("int $3");
//            }

//            if(*(char*)mtod(m_head, char*) == 0x45)
//                kprintf("RTL8139Xmit m_head %08x", *(char*)(mtod(m_head, char*) + 0x28));

//kprintf("\n........RTL8139Xmit line = %d\n", __LINE__);
            if (m_head == NULL)
                break;

            if (Rtl8139_Encap(pThis, m_head)) {
                IF_PREPEND(&ifp->if_snd, m_head);    /*  Case encap fail */
                ifp->if_flags |= IFF_OACTIVE;
                break;
            }

            /*
             * Transmit the frame.
             */
            /*
             * RL_CUR_TXMBUF(x)==>
             * (x->rl_cdata.rl_tx_chain[x->rl_cdata.cur_tx])
             */
            {
//                ECode Rc;
                UInt32 p;

      			addr = (Address)mtod(RL_CUR_TXMBUF(pThis), caddr_t);
//      			Rc = GetPhysicalAddress(addr, (void *)&p);

                p = (UInt32)PhysAddr((char *)addr);


#if (MIPS_ENABLE_CACHE == 1)
        		dma_cache_wback_inv(addr, 128);
#endif

//                if (FAILED(Rc)) {
//                    kprintf("GetPhys failed on %x (%x)\n",
//                          (Address)mtod(RL_CUR_TXMBUF(pThis), caddr_t), Rc);
//                    return -1;
//                }
                CSR_WRITE_4(pThis, RL_CUR_TXADDR(pThis), p);
            }

            /*  mtod(m, t)==> ((t)((m)->m_data)) */
            CSR_WRITE_4(pThis, RL_CUR_TXSTAT(pThis),
                            RL_TXTHRESH(pThis->rl_txthresh) |
                            RL_CUR_TXMBUF(pThis)->m_pkthdr.len
                       );

            RL_INC(pThis->rl_cdata.cur_tx);   /*  Move current Tx index */
        }

        /*
         * We broke out of the loop because all our TX slots are
         * full. Mark the NIC as busy until it drains some of the
         * packets from the queue.
         */
        if (RL_CUR_TXMBUF(pThis) != NULL) {
            /* Tx buffer chain full */
            ifp->if_flags |= IFF_OACTIVE;
        }

        /*
         * Set a timeout in case the chip goes out to lunch.
         */
        ifp->if_timer = 5;

    return 0;
}

int
RTL8139Initalize(RL_SOFTC* pThis)
{
    struct ifnet_        *ifp = &pThis->if_handle->arpcom.ac_if;
    int            s, i;
    UInt32        rxcfg = 0;
    Address addr;


    s = splimp();
    /*
     * Cancel pending I/O and free all RX/TX buffers.
     */
    Rtl8139_Stop(pThis);

    /* Init our MAC address */
    for (i = 0; i < ETHER_ADDR_LEN; i++) {
        CSR_WRITE_1(pThis, RL_IDR0 + i, pThis->if_handle->arpcom.ac_enaddr[i]);
    }

    /* Init the RX buffer pointer register. */
    {
//        ECode Rc;
        UInt32 p = 0;

//        Rc = GetPhysicalAddress((Address)pThis->rl_cdata.rl_rx_buf, (void *)&p);


      	addr = (Address)pThis->rl_cdata.rl_rx_buf;
        p = (UInt32)PhysAddr((char *)addr);

#ifdef _ETHER_DEBUG_
        kprintf("\n BBB addr = %08x p = %08x\n", addr, p);
#endif

//        p = (Address)pThis->rl_cdata.rl_rx_buf;

//        if (FAILED(Rc)) {
//            kprintf("GetPhys failed on %x (%x)\n",
//                  (Address)mtod(RL_CUR_TXMBUF(pThis), caddr_t), Rc);
//            return -1;
//        }
        CSR_WRITE_4(pThis, RL_RXADDR, p);
    }

    /* Init descriptors. */
    Rtl8139_Var_Init(pThis);

    /*
     * Enable transmit and receive.
     */
    CSR_WRITE_1(pThis, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB);

    /*
     * Set the initial TX and RX configuration.
     */
    CSR_WRITE_4(pThis, RL_TXCFG, RL_TXCFG_CONFIG);
    CSR_WRITE_4(pThis, RL_RXCFG, RL_RXCFG_CONFIG);

    /* Set the individual bit to receive frames for this host only. */
    rxcfg = CSR_READ_4(pThis, RL_RXCFG);
    rxcfg |= RL_RXCFG_RX_INDIV;

    /* If we want promiscuous mode, set the allframes bit. */
    if (ifp->if_flags & IFF_PROMISC) {
        rxcfg |= RL_RXCFG_RX_ALLPHYS;
        CSR_WRITE_4(pThis, RL_RXCFG, rxcfg);
    } else {
        rxcfg &= ~RL_RXCFG_RX_ALLPHYS;
        CSR_WRITE_4(pThis, RL_RXCFG, rxcfg);
    }

    /*
     * Set capture broadcast bit to capture broadcast frames.
     */
    if (ifp->if_flags & IFF_BROADCAST) {
        rxcfg |= RL_RXCFG_RX_BROAD;
        CSR_WRITE_4(pThis, RL_RXCFG, rxcfg);
    } else {
        rxcfg &= ~RL_RXCFG_RX_BROAD;
        CSR_WRITE_4(pThis, RL_RXCFG, rxcfg);
    }

    /*
     * Program the multicast filter, if necessary.
     */
    Rtl8139_Setmulti(pThis);

    /*
     * Enable interrupts.
     */
    CSR_WRITE_2(pThis, RL_IMR, RL_INTRS);

    /* Set initial TX threshold */
    pThis->rl_txthresh = RL_TX_THRESH_INIT;

    /* Start RX/TX process. */
    CSR_WRITE_4(pThis, RL_MISSEDPKT, 0);

    /* Enable receiver and transmitter. */
    CSR_WRITE_1(pThis, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB);



    CSR_WRITE_1(pThis, RL_CFG1, RL_CFG1_DRVLOAD|RL_CFG1_FULLDUPLEX);

    ifp->if_flags |= IFF_RUNNING;
    ifp->if_flags &= ~IFF_OACTIVE;

    (void)splx(s);

    return 0;
}


ECode
RTL8139Ioctl(RL_SOFTC* pThis, UInt32 command)
{
    struct ifnet_ *ifp = &pThis->if_handle->arpcom.ac_if;
//    struct ifreq_        *ifr = (struct ifreq *) data;
    int            s, error = 0;
    s = splimp();

    switch(command) {
//    case SIOCSIFADDR:
//    case SIOCGIFADDR:
//    case SIOCSIFMTU:
//        error = ether_ioctl(ifp, command, data);
//        break;
    case SIOCSIFFLAGS:
        if (ifp->if_flags & IFF_UP) {
            RTL8139Initalize(pThis);
        } else {
            if (ifp->if_flags & IFF_RUNNING)
                Rtl8139_Stop(pThis);
        }
        error = 0;
        break;
    case SIOCADDMULTI:
    case SIOCDELMULTI:
        Rtl8139_Setmulti(pThis);
        error = 0;
        break;
    case SIOCGIFMEDIA:
    case SIOCSIFMEDIA:
        break;
    default:
        error = EINVAL;
        break;
    }

    (void)splx(s);

    return(error);
}

void
RTL8139Watchdog(RL_SOFTC* pThis)
{
    struct ifnet_  *ifp = &pThis->if_handle->arpcom.ac_if;

    kprintf("rl%d: watchdog timeout\n", pThis->rl_unit);
    ifp->if_oerrors++;

    Rtl8139_Txeof(pThis);
    Rtl8139_Rxeof(pThis);
    RTL8139Initalize(pThis);

    return;
}

/*
 * Stop the adapter and free any mbufs allocated to the
 * RX and TX lists.
 */
void
Rtl8139_Stop(RL_SOFTC *pThis)
{
    register int        i;
    struct ifnet_        *ifp;

    ifp = &pThis->if_handle->arpcom.ac_if;
    ifp->if_timer = 0;

    CSR_WRITE_1(pThis, RL_COMMAND, 0x00);
    CSR_WRITE_2(pThis, RL_IMR, 0x0000);

    /*
     * Free the TX list buffers.
     */

        for (i = 0; i < RL_TX_LIST_CNT; i++)
        {
            if (pThis->rl_cdata.rl_tx_chain[i] != NULL) {
                m_freem(pThis->rl_cdata.rl_tx_chain[i]);
                pThis->rl_cdata.rl_tx_chain[i] = NULL;
#if defined(_mips)
                CSR_WRITE_1(pThis, RL_TXADDR0 + i, 0x0);
#else
				CSR_WRITE_4(pThis, RL_TXADDR0 + i, 0x0);
#endif
            }
        }

    ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);

    return;
}
